import asyncio
import json
import re
from collections import Counter

import async_lru
import jieba

from app_v2.bili_api.common import UNWANTED_WORDS, STOP_WORDS
from app_v2.bili_api.model import UserInfo, VideoInfo


class Mid:
    _pub_url = "https://app.biliapi.com/x/v2/space/archive/cursor"
    _stat_url = "https://api.bilibili.com/x/space/upstat"
    _pic_url = "https://api.bilibili.com/x/web-interface/card"

    def __init__(self, mid: int | str, session):
        self.mid = mid
        self.session = session

    async def info(self):
        _metadata_stat, _metadata_card = await asyncio.gather(
            self.session.fetch_data(Mid._stat_url, {"mid": self.mid}),
            self.session.fetch_data(Mid._pic_url, {"mid": self.mid}),
            return_exceptions=False  # 根据需求决定是否捕获异常
        )
        return UserInfo(mid=self.mid,
                        name=_metadata_card["data"]["card"]["name"],
                        likes=_metadata_card["data"]["like_num"],
                        videos=_metadata_card["data"]["archive_count"],
                        following=_metadata_card["data"]["card"]["attention"],
                        followers=_metadata_card["data"]["follower"],
                        views=_metadata_stat["data"]["archive"]["view"],
                        pic=_metadata_card["data"]["card"]["face"])

    async def pub_video_bvids(self, ps=None, pn=None):
        data = await self.session.fetch_data(Mid._pub_url, params={"vmid": self.mid})
        return list(map(lambda item: item["bvid"], data["data"]["item"]))

    async def dynamic_info(self):
        url = f"https://app.bilibili.com/x/polymer/web-dynamic/v1/feed/space?offset=&host_mid={self.mid}"
        return await self.session.fetch_data(url)

    @async_lru.alru_cache(maxsize=10, ttl=600)
    async def up_word_cloud(self):
        ids = await self.pub_video_bvids()
        cnt = Counter()

        # 优化1：使用asyncio.gather并发获取视频信息
        async def process_video(vid):
            try:
                video = self.session.video(vid)
                info = await video.info()
                # 并行获取描述、标题和标签
                desc_cut, title_cut, tags = await asyncio.gather(
                    self._cut_text(info.desc),
                    self._cut_text(info.title),
                    info.tags()
                )
                cnt.update(desc_cut)
                cnt.update(title_cut)
                cnt.update(tags)
                return True
            except Exception as e:
                print(f"处理视频 {vid} 时出错: {str(e)}")
                return False

        # 优化2：限制并发数，避免过多并发请求
        semaphore = asyncio.Semaphore(20)  # 同时最多10个并发请求

        async def bounded_process(vid):
            async with semaphore:
                return await process_video(vid)

        # 并发处理所有视频
        await asyncio.gather(*[bounded_process(vid) for vid in ids])

        # 过滤并排序结果
        return sorted(
            filter(lambda x: x[0] not in UNWANTED_WORDS and x[0] not in STOP_WORDS and len(x[0]) > 1, cnt.items()),
            key=lambda x: x[1],
            reverse=True
        )

    # 辅助方法：分词处理
    async def _cut_text(self, text):
        # 使用run_in_executor避免阻塞事件循环
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(None, lambda: list(jieba.cut(text)))

    async def user_word_cloud(self):
        dyn, like, coin = await asyncio.gather(
            self.dynamic_info(),
            self.recent_video_like(),
            self.recent_video_coin(),
        )
        like = [VideoInfo(info, []) for info in like["data"]["list"]]
        coin = [VideoInfo(info, []) for info in coin["data"]]
        like_tags, coin_tags = await asyncio.gather(
            asyncio.gather(*[item.tags() for item in like]),
            asyncio.gather(*[item.tags() for item in coin])
        )
        dyn = json.dumps(dyn, ensure_ascii=False)
        res = re.findall(r'"text": "([^"]*)"', dyn)
        cnt = Counter()
        for item in res:
            cnt.update(jieba.cut(item))

        for item in like_tags:
            cnt.update(item)

        for item in coin_tags:
            cnt.update(item)

        for item in like:
            cnt.update(jieba.cut(item.title))
            cnt.update(jieba.cut(item.desc))

        for item in coin:
            cnt.update(jieba.cut(item.title))
            cnt.update(jieba.cut(item.desc))

        return sorted(
            filter(lambda x: x[0] not in UNWANTED_WORDS and x[0] not in STOP_WORDS and len(x[0]) > 1, cnt.items()),
            key=lambda x: x[1], reverse=True)

    async def recent_video_coin(self):
        url = f"https://api.bilibili.com/x/space/coin/video?vmid={self.mid}"
        return await self.session.fetch_data(url)

    async def recent_video_like(self):
        url = f"https://api.bilibili.com/x/space/like/video?vmid={self.mid}"
        return await self.session.fetch_data(url)

    async def get_followers(self):
        url = "https://api.bilibili.com/x/relation/followings"
        data = await self.session.fetch_data(url)
        return list(map(lambda item: item["mid"], data["data"]["list"]))
